#pragma once

#include "CommInc.h"
#include <assert.h>

template<typename T>
class BlockingQueue final
{
public:
	BlockingQueue() = default;
	~BlockingQueue() = default;

	BlockingQueue(const BlockingQueue& rhs) = delete;
	BlockingQueue& operator=(const BlockingQueue& rhs) = delete;

	void Push(const T& task)
	{
		std::lock_guard<std::mutex> guard(m_Mt);
		m_Queue.emplace(std::move(task));
		m_Cv.notify_one();
	}

	void Push(const T&& task)
	{
		std::lock_guard<std::mutex> guard(m_Mt);
		m_Queue.emplace(task);
		m_Cv.notify_one();
	}

	T Get()
	{
		std::unique_lock<mutex> dtLock(m_Mt);
		while (m_Queue.empty())
		{
			m_Cv.wait(dtLock);
		}
		assert(!m_Queue.empty());

		T data = std::move(m_Queue.front());
		m_Queue.pop();
		return data;
	}

	size_t size() const
	{
		std::lock_guard<std::mutex> guard(m_Mt);
		return m_Queue.size();
	}

private:
	std::mutex m_Mt;
	std::condition_variable m_Cv;
	std::queue<T> m_Queue;
};